package com.medusa.aps.business.modules.basic.mp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.aps.business.model.constant.RedisConstants;
import com.medusa.aps.business.model.pagination.Page;
import com.medusa.aps.business.modules.basic.model.input.MaterialClassificationDTO;
import com.medusa.aps.business.modules.basic.mp.entity.Material;
import com.medusa.aps.business.modules.basic.mp.entity.MaterialClassification;
import com.medusa.aps.business.modules.basic.mp.mapper.MaterialClassificationMapper;
import com.medusa.aps.business.modules.basic.mp.service.MaterialClassificationService;
import com.medusa.aps.business.modules.basic.mp.service.MaterialService;
import com.medusa.aps.business.common.model.resp.SystemCode;
import com.medusa.aps.business.common.redis.annotation.Redisson;
import com.medusa.aps.business.global.model.exception.GlobalException;
import com.medusa.aps.business.global.model.exception.collector.DistinctValidator;
import com.medusa.aps.business.global.model.exception.collector.ErrorCollector;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 物料分类服务实现类
 *
 * @author yuxh
 * @since 2023-08-14 17:37:47
 */
@Service("materialClassificationService")
public class MaterialClassificationServiceImpl extends ServiceImpl<MaterialClassificationMapper, MaterialClassification> implements MaterialClassificationService {

    @Resource
    private MaterialClassificationService materialClassificationService;
    @Resource
    private MaterialService materialService;

    /**
     * 保存物料分类
     *
     * @param materialClassificationDTOS 物料分类dto集合
     */
    @Override
    @Redisson(name = RedisConstants.MATERIAL_CLASSIFICATION_LOCK_KEY, waitTime = 1)
    public void saveMaterialClassification(List<MaterialClassificationDTO> materialClassificationDTOS) {
        validatorParam(materialClassificationDTOS);
        List<MaterialClassification> materialClassifications = materialClassificationDTOS.stream()
                .map(materialClassificationDTO -> new MaterialClassification()
                        .setClassificationName(materialClassificationDTO.getClassificationName())
                        .setDescription(materialClassificationDTO.getDescription())
                ).toList();
        materialClassificationService.saveBatch(materialClassifications);
    }

    private void validatorParam(List<MaterialClassificationDTO> materialClassificationDTOS) {
        ErrorCollector errorCollector = DistinctValidator.valid(materialClassificationDTOS, MaterialClassificationDTO::getClassificationName, "分类名称");
        if (errorCollector.hasError()) {
            throw new GlobalException(errorCollector.toString());
        }
        List<String> classificationNames = materialClassificationDTOS.stream().map(MaterialClassificationDTO::getClassificationName).toList();
        List<MaterialClassification> materialClassifications = materialClassificationService.lambdaQuery()
                .select(MaterialClassification::getClassificationName)
                .in(MaterialClassification::getClassificationName, classificationNames)
                .list();

        if (CollectionUtils.isEmpty(materialClassifications)) {
            return;
        }
        StringBuilder stringBuilder = new StringBuilder();
        List<String> classificationNameDbs = materialClassifications.stream().map(MaterialClassification::getClassificationName).toList();
        for (int i = 0; i < materialClassificationDTOS.size(); i++) {
            MaterialClassificationDTO materialClassificationDTO = materialClassificationDTOS.get(i);
            if (classificationNameDbs.contains(materialClassificationDTO.getClassificationName())) {
                stringBuilder.append(StrUtil.format("第{}行，物料分类名称【{}】系统已存在", i + 1, materialClassificationDTO.getClassificationName()));
            }
        }
        throw new GlobalException(stringBuilder.toString());
    }

    /**
     * 更新物料分类
     *
     * @param materialClassificationDTO 物料分类dto
     * @return 是否更新成功
     */
    @Override
    @Redisson(name = RedisConstants.MATERIAL_CLASSIFICATION_LOCK_KEY, waitTime = 1)
    public Boolean updateMaterialClassification(MaterialClassificationDTO materialClassificationDTO) {
        Integer id = materialClassificationDTO.getId();
        boolean exists = materialClassificationService.lambdaQuery()
                .ne(MaterialClassification::getId, id)
                .eq(MaterialClassification::getClassificationName, materialClassificationDTO.getClassificationName())
                .exists();
        if (exists) {
            throw new GlobalException(StrUtil.format("物料分类名称【{}】系统已存在", materialClassificationDTO.getClassificationName()));
        }
        MaterialClassification classification = materialClassificationService.getById(id);
        if (classification == null) {
            throw SystemCode.PARAM_VALID_ERROR.msgEx("物料分类不存在");
        }
        classification.setClassificationName(materialClassificationDTO.getClassificationName())
                .setDescription(materialClassificationDTO.getDescription());
        return materialClassificationService.lambdaUpdate()
                .eq(MaterialClassification::getId, id)
                .set(MaterialClassification::getClassificationName, classification.getClassificationName())
                .set(MaterialClassification::getDescription, classification.getDescription())
                .update();
    }


    /**
     * 分页查询物料分类
     *
     * @param page               分页条件
     * @param classificationName 物料分类名称
     * @return 物料分页列表
     */

    @Override
    public Page<MaterialClassification> pageMaterialClassification(Page<MaterialClassification> page, String classificationName) {
        return materialClassificationService.lambdaQuery()
                .like(StringUtils.hasText(classificationName), MaterialClassification::getClassificationName, classificationName)
                .page(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(name = RedisConstants.MATERIAL_CLASSIFICATION_LOCK_KEY, waitTime = 1)
    public void deleteMaterialClassification(List<Long> ids) {
        List<Material> materials = materialService.lambdaQuery()
                .select(Material::getMaterialClassificationId)
                .in(Material::getMaterialClassificationId, ids)
                .list();
        if (CollUtil.isNotEmpty(materials)) {
            Set<Integer> materialClassificationIds = materials.stream().map(Material::getMaterialClassificationId).collect(Collectors.toSet());
            materialClassificationService.lambdaQuery()
                    .select(MaterialClassification::getClassificationName)
                    .in(MaterialClassification::getId, materialClassificationIds)
                    .list().stream()
                    .map(MaterialClassification::getClassificationName)
                    .reduce((a, b) -> a + "," + b)
                    .ifPresent(classificationName -> {
                                throw new GlobalException(classificationName + "物料分类分类下存在物料，请先删除物料");
                            }
                    );
        }
        materialClassificationService.removeByIds(ids);
    }


}


